package battle.gameplay;

import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial;


public class TopViewCamera implements AnalogListener{
	
	private float maxLeftAngle = FastMath.PI / 4;
	private float maxRightAngle = FastMath.PI * 3 / 4;
	private float minHeight = FastMath.PI / 4;
	private float maxHeight = FastMath.PI / 2 - 0.01f;
	private float minDistance = 6.0f;
	private float maxDistance = 33.0f;
	private float zoomSpeed = 2.0f;
	private float rotationSpeed = 1.0f;
	
	private boolean enabled = true;
	private Spatial target = null;
	private Camera cam = null;
	private InputManager inputManager;
	private Vector3f initialUpVec;
	
	private float rotation = FastMath.PI / 2;
	private float vRotation = FastMath.PI * 7 / 16;
	private float distance = maxDistance;
	
	public TopViewCamera(Camera cam){
		this.cam = cam;
		initialUpVec = cam.getUp().clone();
	}
	
	public void setTarget(Spatial target){
		this.target = target;
	}
	
	public void onAnalog(String name, float value, float tpf){
		if (name.equals("RotateLeft"))
			rotateCamera(value);
		else if (name.equals("RotateRight"))
			rotateCamera(-value);
		else if (name.equals("RotateUp"))
			vRotateCamera(value);
		else if (name.equals("RotateDown"))
			vRotateCamera(-value);
		else if (name.equals("ZoomIn"))
			zoomCamera(-value);
		else if (name.equals("ZoomOut"))
			zoomCamera(value);
		else if (name.equals("SetDefault"))
			setDefault();
	}
	
	public void registerWithInput(){
		String inputs[] = {"RotateUp", "RotateDown", "RotateLeft", "RotateRight", "ZoomIn", "ZoomOut", "SetDefault"};
		
		inputManager.addMapping("RotateUp", new KeyTrigger(KeyInput.KEY_PGUP));
		inputManager.addMapping("RotateDown", new KeyTrigger(KeyInput.KEY_PGDN));
		inputManager.addMapping("RotateLeft", new KeyTrigger(KeyInput.KEY_HOME));
		inputManager.addMapping("RotateRight", new KeyTrigger(KeyInput.KEY_END));
		inputManager.addMapping("ZoomIn", new KeyTrigger(KeyInput.KEY_EQUALS));
		inputManager.addMapping("ZoomOut", new KeyTrigger(KeyInput.KEY_MINUS));
		inputManager.addMapping("SetDefault", new KeyTrigger(KeyInput.KEY_BACK));
		
		inputManager.addListener(this, inputs);
	}
	
	private void rotateCamera(float value){
		if (!enabled)
			return;
		rotation += value * rotationSpeed;
		if (rotation > maxRightAngle)
			rotation = maxRightAngle;
		if (rotation < maxLeftAngle)
			rotation = maxLeftAngle;
		update();
	}
	
	private void zoomCamera(float value){
		if (!enabled)
			return;
		distance += value * zoomSpeed * 2;
		if (distance > maxDistance)
			distance = maxDistance;
		if (distance < minDistance)
			distance = minDistance;
		if ((vRotation < minHeight))
			vRotation = minHeight;
		update();
	}
	
	private void vRotateCamera(float value){
		if (!enabled)
			return;
		vRotation += value * rotationSpeed;
		if (vRotation > maxHeight)
			vRotation = maxHeight;
		if ((vRotation < minHeight) && (distance > (minDistance + 1.0f)))
			vRotation = minHeight;
		update();
	}
	
	public void setDefault(){
		rotation = FastMath.PI / 2;
		vRotation = FastMath.PI * 7 / 16;
		distance = maxDistance;
	}
	
	public void update(){
		if (target == null)
			return;
		float hDistance = distance * FastMath.sin((FastMath.PI / 2) - vRotation);
		Vector3f pos = new Vector3f(hDistance * FastMath.cos(rotation), distance * FastMath.sin(vRotation), hDistance * FastMath.sin(rotation));
		pos = pos.add(target.getLocalTranslation());
		cam.setLocation(pos);
		cam.lookAt(target.getLocalTranslation(), initialUpVec);
	}
}
